package com.algorithm.qap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.problem.qap.QAPProblem;
import com.util.solution.impl.QAPSolution;

public class ParetoLocalSearch {
	private QAPProblem problem;
	private int run_num;
	public ParetoLocalSearch(QAPProblem problem, int run_num){
		this.problem = problem;
		this.run_num = run_num;
	}
	public void execute(int iteration){
		List<QAPSolution> startList = new ArrayList<QAPSolution>();
		Iterator<QAPSolution> iter = this.problem.exSet.getSolutions().iterator();		
		while(iter.hasNext()){
			QAPSolution t = iter.next();
			try {
				startList.add(t.clone());
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
		}
		
		for(int i=0;i<iteration;i++){
			System.out.println("iteration of : "+(i+1));
			this.PLSexecute(startList);
			startList.clear();
			iter = this.problem.kdStartingSet.getSolutions().iterator();		
			while(iter.hasNext()){
				QAPSolution t = iter.next();
				try {
					startList.add(t.clone());
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}
			}
			this.problem.kdStartingSet.clear();
			this.problem.kdSet.clearAndReset();
		}
		this.problem.kdSet.saveObjectiveResults("files/results/qap/pls/"+problem.fac_num+"-"+problem.obj_num+"/"+this.problem.corr+"/"+this.problem.fac_num+"-"+this.problem.obj_num+"-"+run_num+".txt");
	}
	public void PLSexecute(List<QAPSolution> list){
		Iterator<QAPSolution> iter = list.iterator();
		while(iter.hasNext()){
			QAPSolution s = iter.next();
			this.generateNeighborhood(s);
		}
	}
	/**
	 * generate the neighborhood
	 * @param s
	 */
	public void generateNeighborhood(QAPSolution s){
		int [] seq = s.getLocations().clone();
		for(int i=0;i<problem.fac_num;i++){
			for(int j=i+1;j<problem.fac_num;j++){
				if(i==j) continue;
				int [] changedVal = new int[problem.obj_num];
				for(int k=0;k<problem.obj_num;k++) changedVal[k] = 0;
				for(int k=0;k<problem.obj_num;k++){
					for(int t=0;t<this.problem.fac_num;t++){
						changedVal[k] += 2*(this.problem.distMatrix[i*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+seq[i]*this.problem.fac_num+seq[t]]);
						changedVal[k] += 2*(this.problem.distMatrix[j*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+seq[j]*this.problem.fac_num+seq[t]]);
					}
				}
				QAPSolution temp = new QAPSolution(this.problem.fac_num, this.problem.obj_num, -1);
				temp.setLocations(seq.clone());
				temp.locations[i] = seq[j];
				temp.locations[j] = seq[i];
				for(int k=0;k<this.problem.obj_num;k++){
					for(int t=0;t<this.problem.fac_num;t++){
						changedVal[k] -= 2*(this.problem.distMatrix[i*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+temp.locations[i]*this.problem.fac_num+temp.locations[t]]);
						changedVal[k] -= 2*(this.problem.distMatrix[j*this.problem.fac_num+t]*this.problem.flowMatrix[k*this.problem.fac_num*this.problem.fac_num+temp.locations[j]*this.problem.fac_num+temp.locations[t]]);
					}
				}
				int t_count = 0;
				for(int k=0;k<this.problem.obj_num;k++){
					if(changedVal[k]<=0){
						t_count++;
					}
				}
				if(t_count==this.problem.obj_num){
					continue;
				}
				for(int k=0;k<this.problem.obj_num;k++) temp.object_val[k] = s.object_val[k] - changedVal[k];
				if(this.problem.kdSet.add(temp)){
					this.problem.kdStartingSet.add(temp);
				}
			}
		}
	}
	public static void main(String [] args){
		for(int i=0;i<20;i++){
			QAPProblem qap = new QAPProblem(); 
			new ParetoLocalSearch(qap, i).execute(100);
		}
	}
}
